package com.zxy.supplier_system.server.repository

import com.zxy.supplier_system.server.controller.GoodsBrandController
import com.zxy.supplier_system.server.entity.*
import com.zxy.supplier_system.server.utils.SpecificationUtils
import com.zxy.supplier_system.server.utils.joinOnce
import jakarta.persistence.criteria.JoinType
import org.springframework.data.jpa.domain.Specification
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.JpaSpecificationExecutor

interface GoodsBrandRepository : JpaRepository<GoodsBrand, Int>, JpaSpecificationExecutor<GoodsBrand> {

    fun findAllBySystemServiceOrderByGroup_Id(systemService: SystemService): List<GoodsBrand>

    fun findByIdAndSystemService(id: Int, systemService: SystemService): GoodsBrand?

    fun findFirstByNameAndSystemService(name: String, systemService: SystemService): GoodsBrand?
    fun countAllByGroup(it: GoodsBrandGroup): Int

    object Specifications {

        fun fromQueryGoodsBrandsRequest(queryGoodsBrandsRequest: GoodsBrandController.QueryGoodsBrandsRequest): Specification<GoodsBrand> {
            return Specification.allOf(
                nameContains(queryGoodsBrandsRequest.name)
                    .and(inGroupIds(queryGoodsBrandsRequest.groupIds))
                    .and(disable(queryGoodsBrandsRequest.disable))
            )
        }

        fun isEnable(): Specification<GoodsBrand> {
            return Specification<GoodsBrand> { root, query, criteriaBuilder ->

                criteriaBuilder.or(
                    criteriaBuilder.isFalse(root.get("disable")),
                    criteriaBuilder.isFalse(
                        SpecificationUtils.join<GoodsBrand, Factory>(root, "factory").get("disable")
                    )
                )
            }
        }

        fun isDisable(): Specification<GoodsBrand> {
            return Specification<GoodsBrand> { root, query, criteriaBuilder ->
                val factoryJoin = SpecificationUtils.join<GoodsBrand, Factory>(root, "factory",JoinType.LEFT)
                criteriaBuilder.and(
                    criteriaBuilder.isTrue(root.get("disable")),
                    criteriaBuilder.or(
                        criteriaBuilder.isNull(factoryJoin),
                        criteriaBuilder.isTrue(
                            factoryJoin.get("disable")
                        ),
                    )

                )
            }
        }

        fun disable(disable: Boolean?): Specification<GoodsBrand> {
            return if (disable == null) SpecificationUtils.empty() else if (disable) isDisable() else isEnable()
        }

        fun nameContains(name: String?): Specification<GoodsBrand> {
            return SpecificationUtils.contains({
                it.get("name")
            }, name)
        }

        fun inGroupIds(groupIds: List<Int>): Specification<GoodsBrand> {
            return SpecificationUtils.`in`({ root ->
                root.joinOnce<GoodsBrand, GoodsBrandGroup>("group").get<Int>("id")
            }, groupIds)
        }

        fun inMarketGoods(marketId: Int): Specification<GoodsBrand> {
            return Specification { root, query, criteriaBuilder ->
                val `in` = criteriaBuilder.`in`<Any>(root.get("id"))
                val subQuery = query.subquery(Int::class.java)
                val marketGoodsRoot = subQuery.from(MarketGoods::class.java)
                val marketGoodsGoodsJoin = marketGoodsRoot.join<MarketGoods, Goods>("goods")
                subQuery.select(
                    marketGoodsGoodsJoin.join<Goods, GoodsBrand>("brand").get("id")
                ).distinct(true)
                subQuery.where(
                    criteriaBuilder.equal(
                        marketGoodsRoot.join<MarketGoods, Market>("market").get<Int>("id"),
                        marketId
                    )
                )
                `in`.value(subQuery)
            }
        }


    }

}
